var ENVIRONMENT = "production";

const AZURE_DEV_BASE_API_URL = "https://psladmin.azurewebsites.net/api/";
const AZURE_PRODUCTION_BASE_API_URL = "https://psladminprod.azurewebsites.net/api/";
const LOCAL_BASE_API_URL = "http://localhost:5053/api/";

const API_KEY = "ed99f270-1cab-3ade-822b-81c08e30d57b";
const API_KEY_PARAMETER = "?api_key=" + API_KEY;

let BASE_API_URL = "";

let URLS = {};

const SYSTEM_ID = "PSL";
const JSON_CONTENT_TYPE = "application/json";
const JSON_BODY_HEADERS = {
    "Content-Type": JSON_CONTENT_TYPE
};

export var FILE_API_URL = BASE_API_URL + "file" + API_KEY_PARAMETER;

export const MAX_BUSINESS_CIRCLE_IMAGES = 5;
export const MAX_PROMOTION_IMAGES = 5;

export function setAdminApiEnvironment(environment) {
	ENVIRONMENT = environment;
	if (environment === "development") {
		BASE_API_URL = AZURE_DEV_BASE_API_URL;
		setUrls();
	}
	else if (environment === "production") {
		BASE_API_URL = AZURE_PRODUCTION_BASE_API_URL;
		setUrls();
	}
	else if (environment === "local") {
		BASE_API_URL = LOCAL_BASE_API_URL;
		setUrls();
	}
	else {
		console.log("Invalid environment " + environment);
	}
}

setAdminApiEnvironment(ENVIRONMENT);

function setUrls() {
	console.log("Setting up urls");
	
	URLS.ADMIN_API_URL = BASE_API_URL + "admin/";
	URLS.ADMIN_LOGIN_REQUEST_URL = URLS.ADMIN_API_URL + "login" + API_KEY_PARAMETER;

	URLS.BUSINESS_CIRCLE_API_URL = BASE_API_URL + "business_circle";
	URLS.BUSINESS_CIRCLE_REQUEST_URL = URLS.BUSINESS_CIRCLE_API_URL + API_KEY_PARAMETER;
	URLS.BUSINESS_CIRCLE_MERCHANT_ONBOARD_REQUEST_URL = URLS.BUSINESS_CIRCLE_API_URL + "/merchant/onboard" + API_KEY_PARAMETER;

	URLS.PROMOTION_API_URL = BASE_API_URL + "promotion";
	URLS.PROMOTION_REQUEST_URL = URLS.PROMOTION_API_URL + API_KEY_PARAMETER;
	
	URLS.FILE_API_URL = BASE_API_URL + "file" + API_KEY_PARAMETER;
	
	URLS.MERCHANT_API_URL = BASE_API_URL + "merchant/";
	URLS.MERCHANT_LOGIN_REQUEST_URL = URLS.MERCHANT_API_URL + "login" + API_KEY_PARAMETER;
	
	FILE_API_URL = URLS.FILE_API_URL;
}

export function makeRequest(url, method, headers, data) {
    var jsonBody = data === undefined || data === null? null : JSON.stringify(data);

    console.log("The " + method + " request url is:");
    console.log(url);

    if (hasValue(jsonBody)) {
        console.log("The request json body is:");
	    console.log(jsonBody);
    }
	
	var isNonUniEnvironment = typeof(uni) === "undefined" || 
		typeof(uni?.request) === "undefined";
		
	return new Promise((resolve, reject) => {
        if (isNonUniEnvironment) {
            var requestPromise = fetch(url, {
                method: method || "GET",
                headers: headers,
                body: jsonBody
            });

            handleResponse(requestPromise, resolve, reject);

            return;
        }

        data = data || {};
        uni.request({
            url: url,
            method: method || "GET",
            header: headers,
            data: data,
            success: (res) => {
                handleJsonResponse(res.data, resolve, reject);
            },
            fail: (message) => {
                handleJsonResponse(message, "", reject);
            }
        });
    });
}

export function padToDigits(num, numOfDigits = 2) {
    return num.toString().padStart(numOfDigits, '0');
}

export function formatDate(date = new Date()) {
    return [
        date.getFullYear(),
        padToDigits(date.getMonth() + 1),
        padToDigits(date.getDate()),
    ].join('-');
}

async function handleResponse(requestPromise, resolve, reject) {
    try {
        var response = await requestPromise;
        if (!response.ok) {
            var text = await response.text();
            handleFailResponse(text, "status - " + response.status, reject);
            return;
        }
        var text = await response.text();
        try {
            var json = JSON.parse(text);
            handleJsonResponse(json, resolve, reject);
        } catch(error) {
            handleFailResponse(text, "", reject);
        }
    } catch(error) {
        console.log(error);
        handleFailResponse(error.message, error.cause, reject);
    }
}

function isFailJsonResponse(response) {
    return typeof(response.status) === "number";
}

function handleJsonResponse(jsonResponse, resolve, reject) {
    if (isFailJsonResponse(jsonResponse)) { 
        handleFailJsonResponse(jsonResponse, reject);
        return;
    }

    var error = jsonResponse.error;
    var data = jsonResponse.data;
    if (error.code === 200) {
        resolve(data);
    } else {
        reject(error);
    }
}

function handleFailJsonResponse(jsonResponse, reject) {
    var message = jsonResponse.message || jsonResponse.title;
    var errors = jsonResponse.errors;
    if (hasValue(errors)) {
        for (const key in errors) {
            if (errors.hasOwnProperty(key)) {
                var errorValue = errors[key];
                message += " " + key + ": ";
                if (Array.isArray(errorValue)) {
                    errorValue.forEach(errorItem => {
                        message += errorItem + " ";
                    })
                } else {
                    message += errorValue + "";
                }
            }
        }

        message = message.trim();
    }

    var error = {
        code: jsonResponse.status,
        message,
        user_message: "服务器发生未知错误, 请稍候再试"
    };
    reject(error);
}

function handleFailResponse(message, cause, reject) {
    if (cause === undefined || cause === null || isNaN(cause)) {
        cause = "";
    } else {
        cause = ". " + cause;
    }
    reject({
        code: 500,
        message: "The API service is unaccessible: " + (message || "unknown error") + cause,
        user_message: "后台服务无法访问:" + (message || "未知错误")  + cause
    });
}

export function hasValue(data) {
    return data !== undefined && data !== null;
}

export function addQuery(url, parameterName, parameterValue) {
    if (!hasValue(parameterValue)) {
        return url;
    }
    
    if (parameterValue === true) {
        parameterValue = "true";
    }
    if (parameterValue === false) {
        parameterValue = "false";
    }
    if (url.includes("?"))
        url += "&" ;
    else
        url += "?" ;

    if (Array.isArray(parameterValue)) {
        for (var i = 0; i < parameterValue.length; i++) {
            var value = parameterValue[i];
            url = addQuery(url, parameterName, value);
        }

        return url;
    }

    return url + parameterName + "=" + encodeURI(parameterValue);
}

export function getFileId(url) {
	const fileApiPrefix = "file/";
	var index = url.indexOf(fileApiPrefix);
	if (index === -1) {
		return 0;
	}
	
	var startIndex = index + fileApiPrefix.length;
	var endIndex = url.indexOf("/", startIndex);
	return url.substring(startIndex, endIndex);
}

export async function loginAsAdmin(
    userName, password
) {
    var data = {
        system_id: SYSTEM_ID,
        user_name: userName,
        password: password
    };

    return makeRequest(URLS.ADMIN_LOGIN_REQUEST_URL, "POST", JSON_BODY_HEADERS, data);
}

// If success, returns the created business circle
export async function addBusinessCircle(
    name,
    description,
    creatorAccount,
    imageIds,
    province,
    city,
    county,
    district,
    street,
    addressDetail,
    fullAddress
) {
    var data = {
        system_id : SYSTEM_ID,
        name,
        description,
        creator_account: creatorAccount,
        image_ids: imageIds,
        province,
        city,
        county,
        district,
        street,
        address_detail: addressDetail,
        full_address: fullAddress
    };

    return makeRequest(URLS.BUSINESS_CIRCLE_REQUEST_URL, "POST", JSON_BODY_HEADERS, data);
}

export async function updateBusinessCircle(
    id,
    name,
    description,
    updaterAccount,
    imageIds,
    province,
    city,
    county,
    district,
    street,
    addressDetail,
    fullAddress,
    preifix
) {
    var data = {
        id,
        name,
        description,
        updater_account: updaterAccount,
        image_ids: imageIds,
        province,
        city,
        county,
        district,
        street,
        address_detail: addressDetail,
        full_address: fullAddress,
        preifix
    };

    return makeRequest(URLS.BUSINESS_CIRCLE_REQUEST_URL, "PUT", JSON_BODY_HEADERS, data);
}

export async function deleteBusinessCircle(businessCircleId) {
	let data = {
	    id: businessCircleId
	};
	
	return makeRequest(URLS.BUSINESS_CIRCLE_REQUEST_URL, "DELETE", JSON_BODY_HEADERS, data);
}

export async function onboardMerchant(
    businessCircleId,
    merchantApplyId,
) {
    var data = {
        system_id : SYSTEM_ID,
        business_circle_id: businessCircleId,
        merchant_apply_id: merchantApplyId
    };

    return makeRequest(URLS.BUSINESS_CIRCLE_MERCHANT_ONBOARD_REQUEST_URL, "POST", JSON_BODY_HEADERS, data);
}

// If success, returns the business circles that matches the query
export async function getBusinessCircles(
    account,
    city,
    latitude,
    longitude,
    radius,
	lessData
) {
    var url = URLS.BUSINESS_CIRCLE_REQUEST_URL;
    url = addQuery(url, "system_id", SYSTEM_ID);
    url = addQuery(url, "account", account);
    url = addQuery(url, "city", city);
    url = addQuery(url, "latitude", latitude);
    url = addQuery(url, "longitude", longitude);
    url = addQuery(url, "radius", radius);
	url = addQuery(url, "less_data", lessData);

    return makeRequest(url, "GET");
}

export async function deleteFile(id) {
	return makeRequest(BASE_API_URL + "file/" + id + API_KEY_PARAMETER, "DELETE");
}

export async function addPromotion(
    name,
    description,
    creatorAccount,
    imageIds,
    businessCircleId,
    benefitsCardId,
    startDate,
    endDate
) {
    var data = {
        system_id : SYSTEM_ID,
        name,
        description,
        creator_account: creatorAccount,
        image_ids: imageIds,
        business_circle_id: businessCircleId,
        benefits_card_id: benefitsCardId,
        start_date: startDate,
        end_date: endDate
    };

    return makeRequest(URLS.PROMOTION_REQUEST_URL, "POST", JSON_BODY_HEADERS, data);
}

export async function updatePromotion(
    id,
    name,
    description,
    updaterAccount,
    imageIds,
    businessCircleId,
	benefitsCardId,
	startDate,
	endDate,
	promotionStatusCode
) {
    var data = {
        id,
        name,
        description,
        updater_account: updaterAccount,
        image_ids: imageIds,
		business_circle_id: businessCircleId,
		benefits_card_id: benefitsCardId,
		promotion_status_code: promotionStatusCode,
		start_date: startDate,
		end_date: endDate,
		promotion_status_code: promotionStatusCode
    };

    return makeRequest(URLS.PROMOTION_REQUEST_URL, "PUT", JSON_BODY_HEADERS, data);
}

export async function deletePromotion(id) {
	let data = {
	    id
	};
	
	return makeRequest(URLS.PROMOTION_REQUEST_URL, "DELETE", JSON_BODY_HEADERS, data);
}

export async function getPromotions(
    account, promotionId
) {
    var url = URLS.PROMOTION_REQUEST_URL;
    url = addQuery(url, "system_id", SYSTEM_ID);
    url = addQuery(url, "account", account);
    url = addQuery(url, "promotion_id", promotionId);

    return makeRequest(url, "GET");
}

export async function loginAsMerchant(
	userName, password
) {
	var data = {
		system_id: SYSTEM_ID,
		user_name: userName,
		password: password
	};

	return makeRequest(URLS.MERCHANT_LOGIN_REQUEST_URL, "POST", JSON_BODY_HEADERS, data);
}

export async function loginAsTestAdmin() {
    let userName = "admin";
    let password = "123456";
    var loginResult = await loginAsAdmin(
        userName,
        password
    );

    var realName = loginResult.real_name;
    console.log("Logged in as " + userName + " with real name " + realName);
    return {
        userName,
        realName
    };
}

export async function addTestBusinessCircle(account) {
    let name = "诺德商圈";

    var businessCircle = await addBusinessCircle(
        name,
        "以诺德国际为中心的商圈",
        account,
        [1, 2],
        "广东",
        "深圳",
        "",
        "南山区",
        "前海路",
        "诺德国际8B栋",
        "广东省深圳市南山区前海路诺德国际8B栋"
    );

    console.log("Successfully created business circle with id " + businessCircle.id);
    console.log(businessCircle);

    return businessCircle;
}

export async function addTestBusinessCircle2(account) {
    let name = "翠竹商圈";

    var businessCircle = await addBusinessCircle(
        name,
        "以翠竹地铁站为中心的商圈",
        account,
        [3, 4],
        "广东",
        "深圳",
        "",
        "罗湖区",
        "东门北路",
        "海洋大厦",
        "广东省深圳市罗湖区东门北路海洋大厦"
    );

    console.log("Successfully created business circle with id " + businessCircle.id);
    console.log(businessCircle);

    return businessCircle;
}

export async function onboardTestMerchantApply(businessCircleId) {
    let merchantApplyId = "2";
    console.log("Onboarding merchant with apply id " + merchantApplyId + " to business circle with id " + businessCircleId);
    await onboardMerchant(businessCircleId, merchantApplyId);
    console.log("Successfully onboarded merchant with apply id " + merchantApplyId + " to business circle with id " + businessCircleId);
}

async function sanityTests() {
    let loginResult = await loginAsTestAdmin();
    console.log("Logged in as " + loginResult.realName);

    var loginUsername = loginResult.userName;
    let businessCircle = await addTestBusinessCircle(loginUsername);
    businessCircle = await addTestBusinessCircle2(loginUsername);
    let city = "深圳";
    let businessCirclesOfShenzhen = await getBusinessCircles(null, city, null, null, null);
    console.log("Got " + businessCirclesOfShenzhen.length + " business circles of " + city + ":");
    console.log(businessCirclesOfShenzhen);

    await onboardTestMerchantApply(businessCircle.id);
}

async function runSanityTests() {
    try {
        await sanityTests();
    }
    catch (e) {
        console.log(e);
    }
}

// await runSanityTests();